﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using ElectronicCommerce.Framework.Data.Utility;
using ElectronicCommerce.Framework.Payment.Contract.DataContract;
using ElectronicCommerce.Framework.Payment.Contract.DataContract.Common;
using ElectronicCommerce.Framework.Payment.Contract.DataContract.History;
using ElectronicCommerce.Framework.Payment.Data.Interfaces;

namespace ElectronicCommerce.Framework.Payment.Data.SqlServer
{
    public class SqlChargeHistoryRepository : IChargeHistoryRepository
    {
        #region SQL

        private const string SQL_ChargeRequestHistory_INSERT = @"
            INSERT INTO dbo.PaymentChargeRequestHistory(
                SOID, SODesc, SOAmount, CurrencyCode, SODate, 
                CustomerID, CustomerName, CustomerEmail,
                ShippingContactName, ShippingAddress, ShippingZip, ShippingPhone, ShippingMobile,
                PaymentMethodCode, PaymentMethodName, 
                ContentEncoding, RequestText, RequestDate)
            VALUES(
                @SOID, @SODesc, @SOAmount, @CurrencyCode, @SODate,
                @CustomerID, @CustomerName, @CustomerEmail,
                @ShippingContactName, @ShippingAddress, @ShippingZip, @ShippingPhone, @ShippingMobile,
                @PaymentMethodCode, @PaymentMethodName,
                @ContentEncoding, @RequestText, @RequestDate)
        ";

        private const string SQL_ChargeResponseHistory_INSERT = @"
            INSERT INTO dbo.PaymentChargeResponseHistory(
                SOID, OutSOID, PaymentMethodCode, PaymentMethodName, 
                ResponseMode, ResponseText, ResponseDate, ResultType, ResultMessage)
            VALUES(@SOID, @OutSOID, @PaymentMethodCode, @PaymentMethodName,
                @ResponseMode, @ResponseText, @ResponseDate, @ResultType, @ResultMessage)
        ";

        private const string SQL_ChargeHistory_SELECT = @"
            SELECT TransactionNumber, CustomerID, SOID, SOAmount, CurrencyCode, OutSOID, PaymentMethodCode, PaymentMethodName, Status,
                RequestText, RequestDate, ResponseMode, ResponseText, ResponseDate, ResultType, ResultMessage
            FROM dbo.PaymentChargeHistory(NOLOCK)
            WHERE SOID=@SOID 
        ";

        private const string SQL_ChargeHistory_INSERT_ChargeRequest = @"
            INSERT INTO dbo.PaymentChargeHistory(
                CustomerID, SOID, SOAmount, CurrencyCode, 
                PaymentMethodCode, PaymentMethodName, Status, 
                RequestText, RequestDate)
            VALUES(
                @CustomerID, @SOID, @SOAmount, @CurrencyCode,
                @PaymentMethodCode, @PaymentMethodName, @Status,
                @RequestText, @RequestDate)
        ";

        private const string SQL_ChargeHistory_UPDATE_FOR_Response = @"
            UPDATE dbo.PaymentChargeHistory
            SET OutSOID = @OutSOID,
                Status=@Status, 
                ResponseMode = @ResponseMode,
                ResponseText = @ResponseText,
                ResponseDate = @ResponseDate,
                ResultType = @ResultType,
                ResultMessage = @ResultMessage
            WHERE SOID = @SOID
        ";

        private const string SQL_ChargeHistory_SELECT_OutSOID_BY_SOID = @"
            SELECT OutSOID FROM dbo.PaymentChargeHistory(NOLOCK) WHERE SOID=@SOID
        ";

        #endregion

        /// <summary>
        /// 添加收费请求
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public void InsertChargeRequestHistory(ChargeRequest request)
        {

            using (SqlConnection conn = new SqlConnection(ConnectionStrings.Payment))
            {
                conn.Open();
                using (SqlTransaction tran = conn.BeginTransaction())
                {
                    try
                    {
                        SqlHelper.ExecuteNonQuery(tran, CommandType.Text, SQL_ChargeRequestHistory_INSERT,
                            ChargeRequestHistory_InsertParameters(request));

                        // 查看ChargeHistory是否存在, 不存在则添加支付请求
                        ChargeHistory chargeHistory = GetChargeHistory(request.Order.SOID);
                        if (chargeHistory == null)
                        {
                            SqlHelper.ExecuteNonQuery(tran, CommandType.Text, SQL_ChargeHistory_INSERT_ChargeRequest,
                                ChargeHistory_InsertParameters(request));
                        }

                        tran.Commit();
                    }
                    catch
                    {
                        tran.Rollback();
                        throw;
                    }
                }
            }
        }

        /// <summary>
        /// 添加支付响应，每响应一次记录一次
        /// </summary>
        /// <param name="result"></param>
        public void InsertChargeResponseHistory(ChargeCallbackResult result)
        {
            using (SqlConnection conn = new SqlConnection(ConnectionStrings.Payment))
            {
                conn.Open();
                using (SqlTransaction tran = conn.BeginTransaction())
                {
                    try
                    {
                        SqlHelper.ExecuteNonQuery(tran, CommandType.Text, SQL_ChargeResponseHistory_INSERT,
                            ChargeResponseHistory_InsertParameters(result));

                        // 重复支付不更新
                        if (!Checker.IsPaid(result.SOID))
                        {
                            SqlHelper.ExecuteNonQuery(tran, CommandType.Text, SQL_ChargeHistory_UPDATE_FOR_Response,
                                ChargeHistory_UpdateParameters_For_Response(result));
                        }

                        tran.Commit();
                    }
                    catch
                    {
                        tran.Rollback();
                        throw;
                    }
                }
            }
        }

        /// <summary>
        /// 获取收费交易详情
        /// </summary>
        /// <param name="soID"></param>
        /// <returns></returns>
        public ChargeHistory GetChargeHistory(string soID)
        {
            ChargeHistory chargeHistory = null;

            SqlParameter[] sqlParameters = new SqlParameter[] {
                new SqlParameter("@SOID", soID)            
            };

            using (IDataReader dr = SqlHelper.ExecuteReader(ConnectionStrings.Payment, CommandType.Text,
                SQL_ChargeHistory_SELECT, sqlParameters))
            {
                if (dr.Read())
                {
                    chargeHistory = new ChargeHistory();
                    chargeHistory.TransactionNumber = Convert.ToInt32(dr["TransactionNumber"]);
                    chargeHistory.CustomerID = Convert.ToString(dr["CustomerID"]);
                    chargeHistory.SOID = Convert.ToString(dr["SOID"]);
                    chargeHistory.SOAmount = Convert.ToDecimal(dr["SOAmount"]);
                    chargeHistory.CurrencyCode = (CurrencyCode)Enum.Parse(typeof(CurrencyCode), Convert.ToString(dr["CurrencyCode"]));
                    chargeHistory.OutSOID = Convert.ToString(dr["OutSOID"]);
                    chargeHistory.PaymentMethodCode = Convert.ToString(dr["PaymentMethodCode"]);
                    chargeHistory.PaymnetMethodName = Convert.ToString(dr["PaymentMethodName"]);
                    chargeHistory.ChargeStatus = (PaymentStatus)Convert.ToInt32(dr["Status"]);
                    chargeHistory.RequestText = Convert.ToString(dr["RequestText"]);
                    chargeHistory.RequestDate = Convert.ToDateTime(dr["RequestDate"]);
                    if (dr["ResponseMode"] != DBNull.Value)
                        chargeHistory.ResponseMode = (ResponseMode?)Convert.ToInt32(dr["ResponseMode"]);
                    chargeHistory.ResponseText = Convert.ToString(dr["ResponseText"]);
                    chargeHistory.ResponseDate = Convert.ToDateTime(dr["ResponseDate"]);
                    if (dr["ResultType"] != DBNull.Value)
                        chargeHistory.ResultType = (ChargeCallbackResultType?)Convert.ToInt32(dr["ResultType"]);
                    chargeHistory.ResultMessage = Convert.ToString(dr["ResultMessage"]);
                }
            }

            return chargeHistory;
        }

        /// <summary>
        /// 获取网关交易流水号
        /// </summary>
        /// <param name="soID"></param>
        /// <returns></returns>
        public string GetOutSOID(string soID)
        {
            SqlParameter[] sqlParameters = new SqlParameter[] {
                new SqlParameter("@SOID", soID)            
            };

            return Convert.ToString(SqlHelper.ExecuteScalar(ConnectionStrings.Payment, CommandType.Text,
                SQL_ChargeHistory_SELECT_OutSOID_BY_SOID, sqlParameters));
        }


        #region Sql Parameters

        /// <summary>
        /// 支付请求参数
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        private SqlParameter[] ChargeRequestHistory_InsertParameters(ChargeRequest request)
        {
            SqlParameter[] sqlParameters = new SqlParameter[] {
                new SqlParameter("@SOID", request.Order.SOID),
                new SqlParameter("@SODesc", request.Order.SODesc),
                new SqlParameter("@SOAmount", request.Order.SOAmount),
                new SqlParameter("@CurrencyCode", request.Order.CurrencyCode.ToString()),
                new SqlParameter("@SODate", request.Order.SODate),
                new SqlParameter("@CustomerID", request.Order.Customer.ID),
                new SqlParameter("@CustomerName", request.Order.Customer.Name),
                new SqlParameter("@CustomerEmail", request.Order.Customer.Email),
                new SqlParameter("@ShippingContactName", request.Order.ShippingAddress.ContactName),
                new SqlParameter("@ShippingAddress", request.Order.ShippingAddress.Address),
                new SqlParameter("@ShippingZip", request.Order.ShippingAddress.Zip),
                new SqlParameter("@ShippingPhone", request.Order.ShippingAddress.Phone),
                new SqlParameter("@ShippingMobile", request.Order.ShippingAddress.Mobile),
                new SqlParameter("@PaymentMethodCode", request.Gateway.Code),
                new SqlParameter("@PaymentMethodName", request.Gateway.Name),
                new SqlParameter("@ContentEncoding", request.ContentEncoding),
                new SqlParameter("@RequestText", request.RequestText),
                new SqlParameter("@RequestDate", request.RequestDate),
            };

            return sqlParameters;
        }

        /// <summary>
        /// 支付请求参数
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        private SqlParameter[] ChargeHistory_InsertParameters(ChargeRequest request)
        {
            SqlParameter[] sqlParameters = new SqlParameter[] {
                new SqlParameter("@CustomerID", request.Order.Customer.ID),    
                new SqlParameter("@SOID", request.Order.SOID),    
                new SqlParameter("@SOAmount", request.Order.SOAmount),     
                new SqlParameter("@CurrencyCode", request.Order.CurrencyCode.ToString()),
                new SqlParameter("@PaymentMethodCode", request.Gateway.Code),
                new SqlParameter("@PaymentMethodName", request.Gateway.Name),
                new SqlParameter("@RequestText", request.RequestText),
                new SqlParameter("@RequestDate", request.RequestDate),
                new SqlParameter("@Status", PaymentStatus.InProcess)
            };
            return sqlParameters;
        }

        /// <summary>
        /// 支付响应参数
        /// </summary>
        /// <param name="callbackResult"></param>
        /// <returns></returns>
        private SqlParameter[] ChargeResponseHistory_InsertParameters(ChargeCallbackResult callbackResult)
        {
            SqlParameter[] sqlParameters = new SqlParameter[] {
                new SqlParameter("@SOID", string.IsNullOrEmpty(callbackResult.SOID)?"0":callbackResult.SOID),               
                new SqlParameter("@OutSOID", callbackResult.OutSOID),
                new SqlParameter("@PaymentMethodCode", callbackResult.Gateway.Code),
                new SqlParameter("@PaymentMethodName", callbackResult.Gateway.Name),
                new SqlParameter("@ResponseMode", (int)callbackResult.ResponseMode),
                new SqlParameter("@ResponseText", callbackResult.ResponseText),
                new SqlParameter("@ResponseDate", callbackResult.ResponseDate),
                new SqlParameter("@ResultType", (int)callbackResult.ResultType),
                new SqlParameter("@ResultMessage", callbackResult.ResultMessage)
            };
            return sqlParameters;
        }

        /// <summary>
        /// 支付响应参数
        /// </summary>
        /// <param name="callbackResult"></param>
        /// <returns></returns>
        private SqlParameter[] ChargeHistory_UpdateParameters_For_Response(ChargeCallbackResult callbackResult)
        {
            PaymentStatus chargeStatus = PaymentStatus.InProcess;
            if (callbackResult.ResultType == ChargeCallbackResultType.Success)
            {
                chargeStatus = PaymentStatus.Success;
            }
            else
            {
                chargeStatus = PaymentStatus.Fail;
            }

            SqlParameter[] sqlParameters = new SqlParameter[] {
                new SqlParameter("@SOID", callbackResult.SOID),    
                new SqlParameter("@OutSOID", callbackResult.OutSOID),    
                new SqlParameter("@Status", chargeStatus),   
                new SqlParameter("@PaymentMethodCode", callbackResult.Gateway.Code),
                new SqlParameter("@PaymentMethodName", callbackResult.Gateway.Name),
                new SqlParameter("@ResponseMode", (int)callbackResult.ResponseMode),
                new SqlParameter("@ResponseText", callbackResult.ResponseText),
                new SqlParameter("@ResponseDate", callbackResult.ResponseDate),
                new SqlParameter("@ResultType", (int)callbackResult.ResultType),
                new SqlParameter("@ResultMessage", callbackResult.ResultMessage)
            };
            return sqlParameters;
        }

        #endregion
    }
}
